#include "Ebcot.h"
#include <cmath>
#include <cstdlib>
#include "Bloque.h"
#include "ImagenES.h"
#include "FichBits.h"

#include <iostream>
#include <fstream>

using namespace std;

Ebcot::Ebcot()
{
    //ctor
}

Ebcot::~Ebcot()
{
    //dtor
}


//Obtiene el numero de bitplanes del bloque
int Ebcot::obtenerNumeroBitplanes()
{
    int maximo = 0;

    //Calcula el coeficiente maximo del bloque en valor absoluto
    for(int i =0; i<bloque.getAlto(); i++)
        for(int j = 0; j<bloque.getAncho(); j++)
            if(abs(bloque[i][j] > maximo)) maximo = abs(bloque[i][j]);

    //Devuelve el numero de bitplanes
    return (log2(maximo)+1);

}

//Realiza la fase de propagación sobre el bloque
int Ebcot::Propagacion()
{
    int strip = 0;              //Indicador de la posicion de inicio del strip
    int procesados = 0;         //Contador de coeficientes procesados
    int significativos = 0;     //Contador de coeficientes significativos
    int pred;                   //Prediccion de signo

    //Divide el bloque en strips
    while(strip < bloque.getAlto())
    {
        //recorrer el strip
        for(int j = 0; j < bloque.getAncho();j++)
        {
            for(int i = strip; i< strip+4 && i< bloque.getAlto(); i++)
            {
                //Codificar los coeficientes no significativos con algun vecino significativo
                if(mascaraPropagacion[i][j] && !mascaraRefinamiento[i][j])
                {
                    procesados++; //Aumentamos el contador
                    mascaraLimpieza[i][j]=false; //Indicamos que el coeficiente no debe procesarse en la fase de limpieza
                    //cout << i << " " << j << " -- Puesto a false" << endl;

                    EscribePalabra(8,zeroContext(i,j),CONTEXT); //Escribimos el valor del contexto en el fichero correspondiente

                    if(obtenerBit(i,j))     //Si el coeficiente es significativo...
                    {
                        significativos++;   //Aumentamos el contador
                        anyadeSignificativo(i,j);  //Actualizamos la información de los vecinos

                        EscribeBit(1,STREAM); contEsc += 1; //Codifica el coeficiente y actualiza el contador

                        EscribePalabra(8,signContext(i,j,&pred),CONTEXT);  //Escribe el contexto de signo

                        //Codificamos el signo del coeficiente segun su prediccion
                        if(signo(pred) == signo(bloque[i][j])) {EscribeBit(0,STREAM); contEsc += 1;}
                        else {EscribeBit(1,STREAM); contEsc += 1;}
                    }
                    else //Si no es significativo...
                    {
                        EscribeBit(0,STREAM); contEsc += 1; //Codificamos el coeficiente
                    }
                }
            }
        }

        strip+=4; //Actualiza el valor del indicador de strip
    }

#ifdef SAL2
    if(procesados) cout << "Propagacion:\t" << contEsc << "\t\t" << procesados << "\t\t" << significativos << endl;
#endif

    return procesados;
}

//Pasada de propagacion de decodificacion
void Ebcot::PropagacionDec(int longitud)
{
    int strip = 0;          //Indicador de la posicion de inicio del strip
    int val;                //Valor del bit leido
    int sval;               //Valor del signo leido
    int pred;               //prediccion de signo
    int ctx;                //contexto leido

    //Divide el bloque en strips
    while(strip < bloque.getAlto())
    {
        //recorrer el strip
        for(int j = 0; j < bloque.getAncho();j++)
        {

            for(int i = strip; i< strip+4 && i< bloque.getAlto(); i++)
            {
                //Codificamos los bits significativos en planos anteriores
                if(mascaraPropagacion[i][j] && !mascaraRefinamiento[i][j])
                {
                    mascaraLimpieza[i][j]=false;    //Marcamos que el coeficiente ya ha sido codificado

                    val = LeeBit(STREAM);   //Leemos el bit correspondiente
                    bloque[i][j] |= (val << bitPlaneActual);    //Actualizamos el valor en el bloque
                    ctx = LeePalabra(8,CONTEXT);  //Leemos el contexto del bit (zeroContext)

                    if(val) //Si era significativo
                    {
                        anyadeSignificativo(i,j);
                        sval = LeeBit(STREAM);
                        ctx = LeePalabra(8,CONTEXT); //Leemos el contexto del bit (signContext)

                        if(signContextDec(i,j,&pred) != ctx)
                         {
                            cout << "AVISO: " << i << " " << j <<": Los contextos de signo no coinciden" << endl;
                            cout << "Contextos: " << ctx << " " << signContextDec(i,j,&pred) << endl;
                        }

                        if(sval) pred = -pred; //Si la prediccion fallo, el signo es el opuesto

                        if(pred < 0) mascaraSigno[i][j] = true; //Si el signo es negativo, lo anotamos
                    }
                }
            }
        }
        strip+=4; //Actualizamos el valor del strip
    }
}


//Obtiene el bit del coeficiente para el plano de bit actual
int Ebcot::obtenerBit(int i, int j)
{
    int mask = 1 << bitPlaneActual;     //Calcula la mascara necesaria
    int coef = abs(bloque[i][j]);    //Obtiene el coeficiente

    if(coef & mask) return 1;           //Aplica la mascara y devuelve el resultado
    return 0;
}

//Realiza la fase de limpieza
int Ebcot::Limpieza() //Sin run-length
{
    int strip = 0;              //Indicador de la posicion de inicio del strip
    int procesados = 0;         //Contador de coeficientes procesados
    int pred;                   //Prediccion de signo
    int significativos = 0;     //Contador de coeficientes significativos

    //Divide el bloque en strips
    while(strip < bloque.getAlto())
    {
        //recorrer el strip
        for(int j = 0; j < bloque.getAncho();j++)
        {
            for(int i = strip; i< strip+4 && i< bloque.getAlto(); i++)
            {
                //Codificar los coeficientes no codificados en fases previas
                if(mascaraLimpieza[i][j])
                {
                    procesados++; //Aumentamos el contador

                    EscribePalabra(8,zeroContext(i,j),CONTEXT); //Escribimos el valor del contexto en el fichero correspondiente

                    if(obtenerBit(i,j))     //Si el coeficiente es significativo...
                    {
                        significativos++;   //Aumentamos el contador
                        anyadeSignificativo(i,j);  //Actualizamos la información de los vecinos

                        EscribeBit(1,STREAM); contEsc += 1; //Codifica el coeficiente y actualiza el contador

                        EscribePalabra(8,signContext(i,j,&pred),CONTEXT);  //Escribe el contexto de signo

                        //Codificamos el signo del coeficiente segun su prediccion
                        if(signo(pred) == signo(bloque[i][j])) {EscribeBit(0,STREAM); contEsc += 1;}
                        else {EscribeBit(1,STREAM); contEsc += 1;}
                    }
                    else //Si no es significativo...
                    {
                        EscribeBit(0,STREAM); contEsc += 1; //Codificamos el coeficiente
                    }
                }
            }
        }

        strip+=4; //Actualiza el valor del indicador de strip
    }
    //printInfo();

#ifdef SAL2
    if(procesados) cout << "Limpieza:\t" << contEsc << "\t\t" << procesados << "\t\t" << significativos << endl;
#endif

    return procesados;
}

//Pasada de limpieza de decodificacion
void Ebcot::LimpiezaDec(int longitud)
{
    int strip = 0;          //Indicador de la posicion de inicio del strip
    int val;                //Valor del bit leido
    int sval;               //Valor del signo leido
    int pred;               //prediccion de signo
    int ctx;                //contexto leido

    //Divide el bloque en strips
    while(strip < bloque.getAlto())
    {
        //recorrer el strip
        for(int j = 0; j < bloque.getAncho();j++)
        {

            for(int i = strip; i< strip+4 && i< bloque.getAlto(); i++)
            {
                //Codificamos los bits no significativos en planos anteriores
                if(mascaraLimpieza[i][j])
                {
                    val = LeeBit(STREAM);   //Leemos el bit correspondiente
                    bloque[i][j] |= (val << bitPlaneActual);    //Actualizamos el valor en el bloque
                    ctx = LeePalabra(8,CONTEXT);  //Leemos el contexto del bit (zeroContext)

                    if(val) //Si era significativo
                    {
                        anyadeSignificativo(i,j);
                        sval = LeeBit(STREAM);
                        ctx = LeePalabra(8,CONTEXT); //Leemos el contexto del bit (signContext)

                        if(signContextDec(i,j,&pred) != ctx) //Si los contextos no coinciden damos un aviso
                        {
                            cout << "AVISO: " << i << " " << j <<": Los contextos de signo no coinciden" << endl;
                            cout << "Contextos: " << ctx << " " << signContextDec(i,j,&pred) << endl;
                        }


                        if(sval) pred = -pred; //Si la prediccion fallo, el signo es el opuesto

                        if(pred < 0) mascaraSigno[i][j] = true; //Si el signo es negativo, lo anotamos
                    }
                }
            }
        }
        strip+=4; //Actualizamos el valor del strip
    }
}

//Realiza el paso de Refinamiento
int Ebcot::Refinamiento()
{
    int strip = 0;          //Indicador de la posicion de inicio del strip
    int procesados = 0;     //Contador de coeficientes procesados

    //Divide el bloque en strips
    while(strip < bloque.getAlto())
    {
        //recorrer el strip
        for(int j = 0; j < bloque.getAncho();j++)
        {

            for(int i = strip; i< strip+4 && i< bloque.getAlto(); i++)
            {
                //Codificamos los bits significativos en planos anteriores
                if(mascaraRefinamiento[i][j])
                {
                    procesados++;   //Aumentamos el contador
                    mascaraLimpieza[i][j]=false;   //Indicamos que el coeficiente no debe procesarse en la fase de limpieza

                    if(!info[i][j].fRef) //Si es la pimera vez que se refina el coeficiente...
                    {
                        info[i][j].fRef = true;  //Marcamos el flag

                        //Codifica el contexto correspondiente
                        if(info[i][j].v + info[i][j].h)
                            EscribePalabra(8,MR1,CONTEXT);
                        else EscribePalabra(8,MR0,CONTEXT);
                    }
                    else EscribePalabra(8,MR2,CONTEXT);

                    //Codifica el coeficiente con el valor del bit
                    EscribeBit(obtenerBit(i,j),STREAM); contEsc += 1;
                }
            }
        }
        strip +=4; //Actualiza el indicador de strip
    }



#ifdef SAL2
    if(procesados) cout << "Refinamiento:\t" << contEsc << "\t\t" << procesados << "\t\t" << procesados << endl;
#endif

    return procesados;
}

//Pasada de refinamiento de decodificacion
void Ebcot::RefinamientoDec(int longitud)
{
    int strip = 0;          //Indicador de la posicion de inicio del strip
    int val;                //Valor del bit leido

    //Divide el bloque en strips
    while(strip < bloque.getAlto())
    {
        //recorrer el strip
        for(int j = 0; j < bloque.getAncho();j++)
        {

            for(int i = strip; i< strip+4 && i< bloque.getAlto(); i++)
            {
                //Codificamos los bits significativos en planos anteriores
                if(mascaraRefinamiento[i][j])
                {
                    mascaraLimpieza[i][j]=false;    //Marcamos que el coeficiente ya ha sido codificado

                    val = LeeBit(STREAM);   //Leemos el bit correspondiente
                    bloque[i][j] |= (val << bitPlaneActual);    //Actualizamos el valor en el bloque
                    LeePalabra(8,CONTEXT);  //Leemos el contexto del bit (zeroContext)
                                          //En realidad no necesitamos el contexto
                }
            }
        }
        strip+=4; //Actualizamos el valor del strip
    }
}

//Devuelve el contexto del coeficiente en la posicion (i,j)
int Ebcot::zeroContext(int i, int j)
{
    int V = info[i][j].v;
    int H = info[i][j].h;
    int D = info[i][j].d;


    if(bloque.getBanda() == LL || bloque.getBanda() ==LH)
    {
        if(H == 2) return ZC8;
        if(H == 1)
        {
            if(V >= 1) return ZC7;
            else if(V == 0)
            {
                if(D >= 1) return ZC6;
                else return ZC5;

            }
        }

        else if(H == 0)
        {
            if( V == 2) return ZC4;
            else if(V == 1) return ZC3;
            else if(V == 0)
            {
                if(D >= 2) return ZC2;
                else if(D == 1) return ZC1;
                else return ZC0;

            }
        }

    }
    else if(bloque.getBanda() == HL){
        if(V == 2) return ZC8;
        else if(V == 1)
        {
            if(H >= 1) return ZC7;
            if(H == 0)
            {
                if(D >= 1) return ZC6;
                else return ZC5;
            }

        }
        else if(V == 0)
        {
            if(H == 2) return ZC4;
            else if(H == 1) return ZC3;
            else if(H == 0)
            {
                if(D >= 2) return ZC2;
                else if(D == 1) return ZC1;
                else return ZC0;
            }

        }

    }
    else {
        if(D >= 3) return ZC8;
        else if(D == 2)
        {
            if((H+V) >= 1) return ZC7;
            else return ZC6;
        }
        else if(D == 1)
        {
            if((H+V) >= 2) return ZC5;
            else if((H+V) == 1) return ZC4;
            else  return ZC3;

        }
        else
        {
            if((H+V) >= 2) return ZC2;
            else if((H+V) == 1) return ZC1;
            else return ZC0;
        }

    }

    return -1;
}


//Devuelve el contexto de signo del coeficiente en la posicion (i,j)
//Y su correspondiente preddicion de signo
int Ebcot::signContext(int i, int j, int* prediccion)
{
    //int xH = info[i][j].sH;
    //int xV = info[i][j].sV;

    int xH,xV;
    if(info[i][j].h < 2) xH = 0;
    else
    {
        if(signo(bloque[i][j-1]) == signo(bloque[i][j+1]))
           xH = signo(bloque[i][j-1]);
        else
            xH = 0;
    }

    if(info[i][j].v < 2) xV = 0;
    else
    {
        if(signo(bloque[i-1][j]) == signo(bloque[i+1][j]))
           xV = signo(bloque[i-1][j]);
        else
            xV = 0;
    }

    if(xH > 0)
    {
        *prediccion = -1;

        if(xV > 0) return SC4;
        else if(xV == 0) return SC3;
        else return SC2;
    }

    else if(xH == 0)
    {
        if(xV == 0){ *prediccion = 1; return SC0; }
        else
        {
            if(xV < 0) *prediccion = -1;
            else *prediccion = 1;
            return SC1;
        }
    }
    else
    {
        *prediccion = 1;

        if(xV > 0) return SC2;
        else if(xV == 0) return SC3;
        else return SC4;
    }

    return -1; //Error

}

//Devuelve el contexto de signo del coeficiente en la posicion (i,j)
//Y su correspondiente preddicion de signo
int Ebcot::signContextDec(int i, int j, int* prediccion)
{
    //int xH = info[i][j].sH;
    //int xV = info[i][j].sV;

    int xH,xV;
    if(info[i][j].h < 2) xH = 0;
    else
    {
        if(mascaraSigno[i][j-1] == mascaraSigno[i][j+1])
           (mascaraSigno[i][j-1])? xH = -1 : xH = 1;
        else
            xH = 0;
    }

    if(info[i][j].v < 2) xV = 0;
    else
    {
        if(mascaraSigno[i-1][j] == mascaraSigno[i+1][j])
            (mascaraSigno[i-1][j])? xV = -1 : xV = 1;
        else
            xV = 0;
    }

    if(xH > 0)
    {
        *prediccion = -1;

        if(xV > 0) return SC4;
        else if(xV == 0) return SC3;
        else return SC2;
    }

    else if(xH == 0)
    {
        if(xV == 0){ *prediccion = 1; return SC0; }
        else
        {
            if(xV < 0) *prediccion = -1;
            else *prediccion = 1;
            return SC1;
        }
    }
    else
    {
        *prediccion = 1;

        if(xV > 0) return SC2;
        else if(xV == 0) return SC3;
        else return SC4;
    }

    return -1; //Error

}

//Codifica el bloque con el nombre y numero de bloque indicados
int Ebcot::codifica(const char* nombre,int numero)
{


    int contProp, contRef, contClean;

#ifdef SAL1
    int total;
#endif

    char nombreBloque[100];
    char nombreStream[100];
    char nombreContext[100];
    char nombreLong[100];

    sprintf(nombreBloque,"%s.bl%d",nombre,numero);
    sprintf(nombreStream,"%s.bi%d",nombre,numero);
    sprintf(nombreContext,"%s.ct%d",nombre,numero);
    sprintf(nombreLong,"%s.lp%d",nombre,numero);

    reset();

    if(bloque.CargarBloque(nombreBloque) != 0)
        return -1;

    InicializaEscritura(nombreStream,nombreContext,nombreLong);


    bitPlaneActual = obtenerNumeroBitplanes();

    EscribirCabecera();

    cout << "Ancho: " << bloque.getAncho() << "\tAlto: " << bloque.getAlto() << endl;
    cout << "BitPlanes: " << bitPlaneActual << endl;
    cout << "Subbanda: " << bloque.getBanda() << endl;


    while(bitPlaneActual)
    {

        bitPlaneActual--;
        actualizaSignif();

#ifdef SAL2
        cout << "Plano: " << bitPlaneActual << "\tMascara: " << (0x01 << bitPlaneActual) << endl << endl;
        cout << "Bits:\t\tEscritos\tProcesados\tSignificativos" << endl;
#endif



        contProp = Propagacion();
        contRef = Refinamiento();
        contClean = Limpieza();

        // Por que en ese orden?? Se lo preguntais al profe.
        EscribePalabra(16,contClean,LONG);
        EscribePalabra(16,contRef,LONG);
        EscribePalabra(16,contProp,LONG);



#ifdef SAL1
        total = contProp + contRef + contClean;
#endif

        cout << endl;

#ifdef SAL1
        cout << "-------------------------------------------------" << endl;
        cout << "| PLANO | PASADA        | NUMERO DE COEFICIENTES|" << endl;
        cout << "|       | Propagacion   | " << contProp << "\t\t\t|" << endl;
        cout << "|   " << bitPlaneActual << "   | Refinamiento  | " << contRef << "\t\t\t|" << endl;
        cout << "|       | Clean-up      | " << contClean << "\t\t\t|" << endl;
        cout << "|       | Total         | " << total << "\t\t\t|" << endl;
#endif

    }

    FinalizaEscritura(STREAM);
    FinalizaEscritura(CONTEXT);
    FinalizaEscritura(LONG);

    return 0; //Todo ha ido bien ;)
}

//Reinicia la informacion
void Ebcot::reset()
{
    mascaraPropagacion.limpiarMascara();
    mascaraRefinamiento.limpiarMascara();
    mascaraLimpieza.limpiarMascara(true);
    mascaraSigno.limpiarMascara();

    contEsc = 0;

    for(int i=0;i<64;i++)
    {
        for(int j=0;j<64;j++)
        {
            info[i][j].v = 0;
            info[i][j].h = 0;
            info[i][j].d = 0;
            info[i][j].sV = 0;
            info[i][j].sH = 0;
            info[i][j].fRef = false;
            info[i][j].signif = 0;

        }
    }
}

//Marca los coeficientes que deben codificarse en las pasadas correspondientes
void Ebcot::marcarVecino(int i,int j)
{
    int coef = bloque[i][j];
    info[i][j].signif = 2;

    mascaraRefinamiento[i][j] = true;

    if(i > 0)
    {
        mascaraPropagacion[i-1][j]=true;
        info[i-1][j].sV += signo(coef);
        if(j>0)
        {
            mascaraPropagacion[i-1][j-1]=true;
        }
        if(j<bloque.getAncho()-1)
        {
            mascaraPropagacion[i-1][j+1]=true;
        }
    }
    if(i<bloque.getAlto()-1)
    {
        mascaraPropagacion[i+1][j]=true;
        info[i+1][j].sV += signo(coef);
        if(j>0)
        {
                mascaraPropagacion[i+1][j-1]=true;
        }
        if(j<bloque.getAncho()-1)
        {
                mascaraPropagacion[i+1][j+1]=true;
        }
    }

    if(j>0)
    {
        mascaraPropagacion[i][j-1]=true;
        info[i][j-1].sH += signo(coef);
    }
    if(j<bloque.getAncho()-1)
    {
            mascaraPropagacion[i][j+1]=true;
            info[i][j+1].sH += signo(coef);
    }
}

//Indica a los vecinos que hemos encontrado un coef significativo
void Ebcot::anyadeSignificativo(int i,int j)
{
    if(info[i][j].signif > 0)
    {
        cout << "Marcando dos veces: " << i << " " << j << endl;
    }
    info[i][j].signif = 1;


    if(i > 0)
    {
        info[i-1][j].v++;
        if(j>0)
        {

            info[i-1][j-1].d++;
        }
        if(j<bloque.getAncho()-1)
        {

            info[i-1][j+1].d++;
        }
    }
    if(i<bloque.getAlto()-1)
    {

        info[i+1][j].v++;
        if(j>0)
        {

                info[i+1][j-1].d++;
        }
        if(j<bloque.getAncho()-1)
        {

                info[i+1][j+1].d++;
        }
    }

    if(j>0)
    {

        info[i][j-1].h++;
    }
    if(j<bloque.getAncho()-1)
    {

            info[i][j+1].h++;
    }
}

//Marca los vecinos que hemos encontrado significativos en este plano
void Ebcot::actualizaSignif()
{
    for(int i=0; i < bloque.getAlto();i++)
        for(int j=0; j < bloque.getAncho();j++)
            if(info[i][j].signif == 1)
                marcarVecino(i,j);
}

//Devuelve el valor del signo
// 1 = positivo, -1 = negativo, 0 = sin signo
int Ebcot::signo(int v)
{
    return (v>0) - (v<0);
}

int Ebcot::decodifica(const char* nombre, int numBloque)
{
    char nombreBloque[100];
    char nombreStream[100];
    char nombreContext[100];
    char nombreLong[100];

    int ancho, alto, nivel, subbanda;
    int longClean, longRef, longProp;

    //Obtenemos los nombres de los archivos
    sprintf(nombreBloque,"%srec.bl%d",nombre,numBloque);
    sprintf(nombreStream,"%s.bi%d",nombre,numBloque);
    sprintf(nombreContext,"%s.ct%d",nombre,numBloque);
    sprintf(nombreLong,"%s.lp%d",nombre,numBloque);

    if(InicializaLectura(nombreStream,nombreContext,nombreLong))
    {
            cout << "Error abriendo los archivos de lectura" << endl;
            return -1;
    }

    //Reiniciamos la información del bloque
    reset();

    //Leemos la cabecera del bloque
    ancho = LeePalabra(8,LONG);
    alto = LeePalabra(8,LONG);
    nivel = LeePalabra(8,LONG);
    subbanda = LeePalabra(8,LONG);
    bitPlaneActual = LeePalabra(8,LONG) + 1;

    //Creamos el bloque resultado
    bloque.CrearBloque(ancho,alto,nivel,subbanda);

    //Leemos la logitud de las pasadas en este plano
    longClean = LeePalabra(16,LONG);
    longRef = LeePalabra(16,LONG);
    longProp = LeePalabra(16,LONG);

    while(bitPlaneActual)
    {
        //Actualizamos el plano
        bitPlaneActual--;

        //Actualizamo los valore que ha sido significativos
        //De modo que se actualicen las mascaras
        actualizaSignif();

        //Decodificamos las tres pasadas
        PropagacionDec(longProp);
        RefinamientoDec(longRef);
        LimpiezaDec(longClean);
    }

    //Ajustamos el signo de los coeficientes
    ajustaSigno();

    //Cerramso los archivos de lectura
    FinalizaLectura(STREAM);
    FinalizaLectura(CONTEXT);
    FinalizaLectura(LONG);

    //Ecribimos el bloque
    bloque.GuardarBloque(nombreBloque);

    return 0;
}

//Ajusta el signo de los coeficientes negativos
void Ebcot::ajustaSigno()
{
    for(int i=0; i<bloque.getAlto();i++)
    {
        for(int j=0; j<bloque.getAncho();j++)
        {
            if(mascaraSigno[i][j])      //Si el coeficiente es negativo cambia el signo
                bloque[i][j] = -bloque[i][j];
        }
    }
}

//Escribe la cabecera en los archivos .lpx
void Ebcot::EscribirCabecera()
{
    EscribePalabra(8,bloque.getAncho(),LONG);
    EscribePalabra(8,bloque.getAlto(),LONG);
    EscribePalabra(8,bloque.getNivel(),LONG);
    EscribePalabra(8,bloque.getBanda(),LONG);
    EscribePalabra(8,bitPlaneActual-1,LONG);
}


//DEBUG

void Ebcot::printInfo()
{
    cout << endl;
    for(int i=0; i < bloque.getAlto();i++)
    {
        for(int j=0; j < bloque.getAlto();j++)
        {
            if(info[i][j].signif == 2) cout << "x";
            else if(info[i][j].signif == 1) cout << "O";
            else cout << "-";
        }
        cout << endl;
    }
}














